<?php namespace App\Libraries;

/**
 *
 */
class Datatable {
    private $db;
    private $build;
    private $table        = [];
    private $select       = [];
    private $where        = [];
    private $orWhere      = [];
    private $whereIn      = [];
    private $orWhereIn    = [];
    private $whereNotIn   = [];
    private $orWhereNotIn = [];
    private $like         = [];
    private $orLike       = [];
    private $notLike      = [];
    private $orNotLike    = [];
    private $join         = [];
    private $groupBy      = [];
    private $limit;

    public function __construct($table = "") {
        $this->db = \Config\Database::connect();
        $this->db->initialize();
        if (isset($table)) {
            $this->table($table);
        }
    }

    public function table($table) {
        $this->table = $table;
        $this->build = $this->db->table($table);
        return $this;
    }

    public function where($key, $val = null, $backtick = true) {
        $this->where[] = [$key, $val, $backtick];
        $this->build->where($key, $val, $backtick);
        return $this;
    }

    public function orWhere($key, $val = null, $backtick_protect = true) {
        $this->orwhere[] = [$key, $val, $backtick];
        $this->build->orWhere($key, $val, $backtick);
        return $this;
    }

    public function whereIn($key, $val = null) {
        $this->whereIn[] = array($key, $val);
        $this->build->whereIn($key, $val);
        return $this;
    }

    public function orWhereIn($key, $val = null) {
        $this->orWhereIn[] = array($key, $val);
        $this->build->orWhere($key, $val);
        return $this;
    }

    public function whereNotIn($key, $val = null) {
        $this->whereNotIn[] = array($key, $val);
        $this->build->whereNotIn($key, $val);
        return $this;
    }

    public function orWhereNotIn($key, $val = null) {
        $this->orWhereNotIn[] = array($key, $val);
        $this->build->orWhereNotIn($key, $val);
        return $this;
    }

    public function select($select) {
        $this->select = $select;
        $this->build->select($select);
        return $this;
    }

    public function like($key, $val = null, $side = 'both') {
        $this->like[] = array($key, $val, $side);
        $this->build->like($key, $val, $side);
        return $this;
    }

    public function orLike($key, $val = null, $side = 'both') {
        $this->orLike[] = array($key, $val, $side);
        $this->build->orLike($key, $val, $side);
        return $this;
    }

    public function notLike($key, $val = null, $side = 'both') {
        $this->notLike[] = array($key, $val, $side);
        $this->build->notLike($key, $val, $side);
        return $this;
    }

    public function orNotLike($key, $val = null, $side = 'both') {
        $this->orNotLike[] = array($key, $val, $side);
        $this->build->orNotLike($key, $val, $side);
        return $this;
    }

    public function join($table, $fk, $type = null) {
        $this->join[] = array($table, $fk, $type);
        $this->build->join($table, $fk, $type);
        return $this;
    }

    public function groupBy($val) {
        $this->groupBy[] = $val;
        $this->build->groupBy($val);
        return $this;
    }

    public function orderBy($order, $asc = 'ASC') {
        $this->build->orderBy($order, $asc);
        return $this;
    }

    public function limit($limit, $offset) {
        $this->limit[] = array($limit, $offset);
        $this->build->limit($limit, $offset);
        return $this;
    }

    private function countResults() {
        foreach ($this->join as $val) {
            $this->build->join($val[0], $val[1], $val[2]);
        }
        foreach ($this->where as $val) {
            $this->build->where($val[0], $val[1], $val[2]);
        }
        foreach ($this->orWhere as $val) {
            $this->build->orWhere($val[0], $val[1], $val[2]);
        }
        foreach ($this->whereIn as $val) {
            $this->build->whereIn($val[0], $val[1]);
        }
        foreach ($this->orWhereIn as $val) {
            $this->build->orWhereIn($val[0], $val[1]);
        }
        foreach ($this->whereNotIn as $val) {
            $this->build->whereNotIn($val[0], $val[1]);
        }
        foreach ($this->orWhereNotIn as $val) {
            $this->build->orWhereNotIn($val[0], $val[1]);
        }
        foreach ($this->groupBy as $val) {
            $this->build->groupBy($val);
        }
        foreach ($this->like as $val) {
            $this->build->like($val[0], $val[1], $val[2]);
        }
        foreach ($this->orLike as $val) {
            $this->build->orLike($val[0], $val[1], $val[2]);
        }
        foreach ($this->notLike as $val) {
            $this->build->notLike($val[0], $val[1], $val[2]);
        }
        foreach ($this->orNotLike as $val) {
            $this->build->orNotLike($val[0], $val[1], $val[2]);
        }

        return $this->build->countAllResults();
    }

    public function json() {
        $results = $this->build->get()
                               ->getResultArray();
        $count = $this->countResults();
        return json_encode(['total' => $count, 'rows' => $results]);
    }
}
